package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"

	"server/src/protocol808"
)

const (
	ResultSuccess int = 1
	ResultFaild   int = 0
)

type MichelinHTTPServer struct {
	cfg        *Config
	manager    *ConnManager
	dbo        *DBOperation
	whiteLists *HTTPWhiteLists
	serialNo   uint16
}

func NewMichelinHTTPServer(config *Config, dbo *DBOperation, connManager *ConnManager) *MichelinHTTPServer {
	c := MichelinHTTPServer{cfg: config, dbo: dbo, manager: connManager}
	c.whiteLists = NewHTTPWhiteLists(dbo)
	return &c
}

func (p *MichelinHTTPServer) Listen() {
	sPort := fmt.Sprintf(":%d", p.cfg.MichelinHttpPort)

	http.HandleFunc("/whitelist/list", p.WhiteLists)
	http.HandleFunc("/whitelist/add", p.WhiteListAdd)
	http.HandleFunc("/whitelist/remove", p.WhiteListRemove)

	http.HandleFunc("/Tire/CheckSerialNumber", p.CheckSerialNumber)
	http.HandleFunc("/Tire/SetTirePressureValue", p.SetTirePressureValue)
	http.HandleFunc("/Tire/ChangeTire", p.ChangeTire)

	zLog(nil, "接收器服务器开始监听米其林小车组HTTPS端口:", sPort)

	go func() {
		zLog(nil, "开始监听端口:", sPort, " HTTPS:", p.cfg.HTTPS)
		var err error
		if p.cfg.HTTPS {
			err = http.ListenAndServeTLS(sPort, p.cfg.CertFile, p.cfg.KeyFile, nil)
		} else {
			err = http.ListenAndServe(sPort, nil)
		}
		if err != nil {
			zLog(nil, "米其林小车组HTTPS监听失败:", err)
		}
	}()
}

/*

func (p *HTTPServices) DispatchCommand(w http.ResponseWriter, req *http.Request) {
	if p.commonCheck(&w, req) {
		req.ParseForm()
		rid := req.FormValue("rid")
		command := req.FormValue("command")

		if p.checkFields(&w, rid, command) {
			conn := p.manager.Get(rid)
			if conn == nil {

				s := p.makeResultStr(0, rid+"不在线，命令已保存到数据库中")
				w.Write([]byte(s))
			} else {
				buf := conn.hexStr2Bytes(command)
				conn.SafeSend(buf)
			}

		}
	}
}
*/

type CheckSerialNumberT struct {
	SN string `json:"SN"`
}

func (p *MichelinHTTPServer) CheckSerialNumber(w http.ResponseWriter, req *http.Request) {
	if p.commonCheck(&w, req) {
		buf, ok := p.readBody(&w, req)

		if ok {
			var csn CheckSerialNumberT
			var sResult string
			err := json.Unmarshal(buf, &csn)
			if err != nil {
				sResult = p.makeResultStr(ResultFaild, "内容格式错误，不是JSON格式")
				w.Write([]byte(sResult))
				return
			}

			ok = p.dbo.CheckSerialNumber(p.cfg.MichelinID, csn.SN)
			if ok {
				sResult = p.makeResultStr(ResultSuccess, "序列号存在")
			} else {
				sResult = p.makeResultStr(ResultFaild, "该序列号不存在")
			}
			w.Write([]byte(sResult))
		}
	}
}

type ChangeTireT struct {
	SN            string
	WheelPlaceOld string
	WheelPlaceNew string
	cardIdOld     int
	snOld         int
	cardIdNew     int
	snNew         int
}

func (p *ChangeTireT) splitCardIdAndSN(str string) (int, int) {
	var cardid, sn int

	if str != "" {
		index := strings.Index(str, "-")
		if index >= 0 {
			sCardId := str[:index]
			cardid, _ = strconv.Atoi(sCardId)
			sSN := str[index+1:]
			sn, _ = strconv.Atoi(sSN)
		}
	}

	return cardid, sn
}

func (p *ChangeTireT) Parse() {
	p.cardIdOld, p.snOld = p.splitCardIdAndSN(p.WheelPlaceOld)
	p.cardIdNew, p.snNew = p.splitCardIdAndSN(p.WheelPlaceNew)
}

func (p *MichelinHTTPServer) ChangeTire(w http.ResponseWriter, req *http.Request) {
	if p.commonCheck(&w, req) {
		buf, ok := p.readBody(&w, req)

		if ok {
			var ct ChangeTireT
			var sResult string
			err := json.Unmarshal(buf, &ct)
			if err != nil {
				sResult = p.makeResultStr(ResultFaild, "内容格式错误，不是JSON格式")
				w.Write([]byte(sResult))
				return
			}

			res := p.dbo.GetRelations(ct.SN)
			if res != nil {

				ct.Parse()

				var relationOld, relationNew, relation *TireRelationT
				for i := 0; i < len(res); i++ {
					relation = &res[i]
					if relation.CardId == ct.cardIdNew && relation.SN == ct.snNew {
						relationNew = relation
					} else if relation.CardId == ct.cardIdOld && relation.SN == ct.snOld {
						relationOld = relation
					}
					if relationNew != nil && relationOld != nil {
						break
					}
				}
				if relationNew == nil || relationOld == nil {
					sResult = p.makeResultStr(ResultFaild, "指定的轮位还未绑定设备")
				} else {

					relationNew.Sid, relationOld.Sid = relationOld.Sid, relationNew.Sid
					relationNew.TireNo, relationOld.TireNo = relationOld.TireNo, relationNew.TireNo

					p.dbo.ReplaceSensorId(relationNew.Oid, relationNew.Sid, relationNew.TireNo)
					p.dbo.ReplaceSensorId(relationOld.Oid, relationOld.Sid, relationOld.TireNo)

					p.serialNo++
					bindSendor := protocol808.CommandBindSensorToPosition{}
					bindSendor.Sensors = make([]protocol808.SensorPositionT, 0)
					bindSendor.TerminalId = ct.SN
					bindSendor.CommandId = protocol808.CommandIdBindTireToPosition
					bindSendor.OperateModel = protocol808.CommandOperateModelSet
					bindSendor.SerialNo = p.serialNo
					for _, v := range res {
						sensor := protocol808.SensorPositionT{SensorId: v.Sid, CardId: v.CardId, SerialNo: v.SN}
						bindSendor.Sensors = append(bindSendor.Sensors, sensor)
					}

					message, command := bindSendor.Pack()
					err = p.SendCommand(ct.SN, p.serialNo, message, command)

					if err == nil {
						sResult = p.makeResultStr(ResultSuccess, "互换成功")
					} else {
						sResult = p.makeResultStr(ResultSuccess, "互换失败")
					}
				}
			} else {
				sResult = p.makeResultStr(ResultFaild, "该设备暂无传感器信息")
			}
			w.Write([]byte(sResult))
		}
	}
}

type SetTirePressureValueT struct {
	SN            string
	Axis1Pressure float64
	Axis2Pressure float64
}

func (p *MichelinHTTPServer) SetTirePressureValue(w http.ResponseWriter, req *http.Request) {
	if p.commonCheck(&w, req) {
		buf, ok := p.readBody(&w, req)

		if ok {
			var stpv SetTirePressureValueT
			var sResult string
			err := json.Unmarshal(buf, &stpv)
			if err != nil {
				sResult = p.makeResultStr(ResultFaild, "内容格式错误，不是JSON格式")
				w.Write([]byte(sResult))
				return
			}

			p.serialNo++
			setTirePressure := protocol808.CommandMichelinSetTirePressure{}
			setTirePressure.SerialNo = p.serialNo
			setTirePressure.TerminalId = stpv.SN
			setTirePressure.Axis1Pressure = stpv.Axis1Pressure
			setTirePressure.Axis2Pressure = stpv.Axis2Pressure

			message, command := setTirePressure.Pack()
			err = p.SendCommand(stpv.SN, p.serialNo, message, command)

			if err == nil {
				sResult = p.makeResultStr(ResultSuccess, "设置成功")
			} else {
				sResult = p.makeResultStr(ResultSuccess, "设置失败")
			}
			w.Write([]byte(sResult))
		}
	}
}

func (p *MichelinHTTPServer) WhiteLists(w http.ResponseWriter, req *http.Request) {
	if p.checkLocal(req.RemoteAddr) {
		ips := p.whiteLists.List()
		buf, _ := json.Marshal(ips)
		w.Write(buf)
	} else {
		w.Write([]byte("Just for local IP"))
	}
}

func (p *MichelinHTTPServer) WhiteListAdd(w http.ResponseWriter, req *http.Request) {
	if p.checkLocal(req.RemoteAddr) {
		req.ParseForm()
		ip := req.FormValue("ip")
		if ip != "" && ip != "127.0.0.1" {
			p.whiteLists.Add(ip)
			w.Write([]byte("Done!"))
		} else {
			w.Write([]byte("IP can't be empty"))
		}
	} else {
		w.Write([]byte("Just for local IP"))
	}
}

func (p *MichelinHTTPServer) WhiteListRemove(w http.ResponseWriter, req *http.Request) {
	if p.checkLocal(req.RemoteAddr) {
		req.ParseForm()
		ip := req.FormValue("ip")
		if ip != "" && ip != "127.0.0.1" {
			p.whiteLists.Remove(ip)
			w.Write([]byte("Done!"))
		} else {
			w.Write([]byte("IP can't be empty"))
		}
	} else {
		w.Write([]byte("Just for local IP"))
	}
}

func (p *MichelinHTTPServer) SendCommand(rid string, serialNo uint16, message string, command string) error {

	oid := p.dbo.SaveCommand(rid, serialNo, message, command)

	var err error

	conn := p.manager.Get(rid)
	if conn == nil {
		zLog(nil, rid, "当前不在线，命令已保存到数据库中")

	} else {
		buf := conn.hexStr2Bytes(message)
		err = conn.SafeSend(buf)
		if err == nil {
			zLog(conn.conn, rid, "下发指令：", message, " 成功")
			go p.dbo.SetCommandStatus(oid, CommandStatusSent)
		} else {
			zLog(conn.conn, rid, "下发指令：", message, " 失败：", err.Error())
		}
	}
	return nil
}

func (p *MichelinHTTPServer) commonCheck(w *http.ResponseWriter, req *http.Request) bool {
	(*w).Header().Add("Access-Control-Allow-Origin", "*")

	var s string
	if req.Method != "POST" {
		s = p.makeResultStr(0, "无效的访问方式")
		(*w).Write([]byte(s))
		return false
	}

	ip := req.RemoteAddr
	if !p.whiteLists.Exists(ip) {
		ip = p.whiteLists.trimIP(ip)
		s = p.makeResultStr(0, ip+" 不在白名单中，请与管理人员联系")
		(*w).Write([]byte(s))
		return false
	}
	return true

	/*
		userid = ""
		result = false

		query := req.URL.Query()


		userid = query.Get("userid")
		accesstoken := query.Get("accesstoken")
		if !p.checkFields(w, userid, accesstoken) {
			return
		}


		if p.ac.Check(userid, accesstoken) {
			s := p.makeResultStr(1006, "非法访问")
			(*w).Write([]byte(s))
			return
		}
		if req.Method != "POST" {
			s := p.makeResultStr(1002, "无效的访问方式")
			(*w).Write([]byte(s))
			return
		}

		result = true

		return
	*/
}

func (p *MichelinHTTPServer) checkLocal(ip string) bool {
	index := strings.Index(ip, ":")
	if index >= 0 {
		ip = ip[0:index]
	}

	return ip == "127.0.0.1"
}

/*

func (p *MichelinHTTPServer) checkFields(w *http.ResponseWriter, fields ...string) bool {
	for _, field := range fields {
		if field == "" {
			s := p.makeResultStr(1003, "缺少必要的字段")
			(*w).Write([]byte(s))
			return false
		}
	}
	return true
}
*/

func (p *MichelinHTTPServer) makeResultStr(code int, msg string) string {
	return fmt.Sprintf(`{"State":%d,"Message":"%s"}`, code, msg)
}

func (p *MichelinHTTPServer) readBody(w *http.ResponseWriter, req *http.Request) ([]byte, bool) {
	buf, err := ioutil.ReadAll(req.Body)
	defer req.Body.Close()

	if err != nil || buf == nil {
		sErr := p.makeResultStr(ResultFaild, "内容为空，无效请求")
		(*w).Write([]byte(sErr))
		return nil, false
	}

	return buf, true
}
